package cn.anecansaitin.jep.parser.ast.node.expression;

import cn.anecansaitin.jep.parser.ast.node.NodeCreationResult;
import cn.anecansaitin.jep.types.TypeInfo;
import org.jetbrains.annotations.Nullable;

/// 三元表达式
public final class Ternary extends Expression {
    private final Expression condition;
    private final Expression trueValue;
    private final Expression falseValue;

    public Ternary(Expression condition, Expression trueValue, Expression falseValue, TypeInfo resultType, int line, int column) {
        super(resultType, line, column);
        this.condition = condition;
        this.trueValue = trueValue;
        this.falseValue = falseValue;
    }

    public Expression condition() {
        return condition;
    }

    public Expression trueValue() {
        return trueValue;
    }

    public Expression falseValue() {
        return falseValue;
    }

    public static NodeCreationResult<Ternary> create(Expression condition, Expression trueValue, Expression falseValue, int line, int column) {
        TypeInfo typeInfo = analyzeTypeResult(trueValue, falseValue);

        if (typeInfo == null) {
            return NodeCreationResult.fail("三元表达式类型解析错误");
        }

        return NodeCreationResult.success(new Ternary(condition, trueValue, falseValue, typeInfo, line, column));
    }

    @Nullable
    private static TypeInfo analyzeTypeResult(Expression trueValue, Expression falseValue) {
        TypeInfo trueType = trueValue.resultType();
        TypeInfo falseType = falseValue.resultType();

        return switch (trueType) {
            case BOOLEAN -> {
                if (falseType == TypeInfo.BOOLEAN) {
                    yield TypeInfo.BOOLEAN;
                } else {
                    yield null;
                }
            }
            case BYTE -> switch (falseType) {
                case BYTE, INT -> TypeInfo.BYTE;
                case CHAR -> TypeInfo.INT;
                case LONG -> TypeInfo.LONG;
                case FLOAT -> TypeInfo.FLOAT;
                case DOUBLE -> TypeInfo.DOUBLE;
                default -> null;
            };
            case SHORT -> switch (falseType) {
                case BYTE, SHORT -> TypeInfo.SHORT;
                case INT, CHAR -> TypeInfo.INT;
                case LONG -> TypeInfo.LONG;
                case FLOAT -> TypeInfo.FLOAT;
                case DOUBLE -> TypeInfo.DOUBLE;
                default -> null;
            };
            case INT -> switch (falseType) {
                case BYTE -> TypeInfo.BYTE;
                case INT, CHAR, SHORT -> TypeInfo.INT;
                case LONG -> TypeInfo.LONG;
                case FLOAT -> TypeInfo.FLOAT;
                case DOUBLE -> TypeInfo.DOUBLE;
                default -> null;
            };
            case LONG -> switch (falseType) {
                case BYTE, SHORT, INT, CHAR, LONG -> TypeInfo.LONG;
                case FLOAT -> TypeInfo.FLOAT;
                case DOUBLE -> TypeInfo.DOUBLE;
                default -> null;
            };
            case FLOAT -> switch (falseType) {
                case BYTE, SHORT, INT, CHAR, LONG, FLOAT -> TypeInfo.FLOAT;
                case DOUBLE -> TypeInfo.DOUBLE;
                default -> null;
            };
            case DOUBLE -> switch (falseType) {
                case BYTE, SHORT, INT, CHAR, LONG, FLOAT, DOUBLE -> TypeInfo.DOUBLE;
                default -> null;
            };
            case CHAR -> switch (falseType) {
                case CHAR -> TypeInfo.CHAR;
                case BYTE, SHORT, INT -> TypeInfo.INT;
                case LONG -> TypeInfo.LONG;
                case FLOAT -> TypeInfo.FLOAT;
                case DOUBLE -> TypeInfo.DOUBLE;
                default -> null;
            };
            case STRING -> switch (falseType) {
                case STRING -> TypeInfo.STRING;
                default -> null;
            };
            default -> null;
        };
    }
}